﻿/// <reference path="../../../../_3rd part/SharePoint.d.ts"/>
/// <reference path="../../../../_3rd part/MicrosoftAjax.d.ts"/>

/// <reference path="../../../../_3rd part/SP.GanttControl.d.ts"/>
/// <reference path="../../../../_3rd part/SP.JsGrid.d.ts"/>

module spdevlab {

    export module fields {

        export class VisaFieldHelper {

            public static UpdateValues(textBoxes: HTMLInputElement[], value: string) {
                for (var i = 0; i < textBoxes.length; i++) {
                    textBoxes[i].value = VisaFieldHelper.ParseValuePart(value, i);
                }
            }

            public static ParseValuePart(value: string, partIndex: number): string {

                // TODO, add "-" delimiter char support
                if (value && (value.length == 16)) {
                    return value.substring(partIndex * 4, (partIndex + 1) * 4);
                }

                return "";
            }
        }

        export class VisaField {

            _fieldName: string;
            _fieldIds: string[] = [];
            _errorContainerId: string = null;

            constructor(fieldName: string) {
                this._fieldName = fieldName;
            }

            private _wrapIntoInput(renderCtx: SPClientTemplates.RenderContext_Form, val: string, index: number): string {

                var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(renderCtx);
                var inputContainerId = formCtx.fieldName + '_' + formCtx.fieldSchema.Id + '_VisaField_' + index;

                this._fieldIds[index] = inputContainerId;

                return "<input type='text' id='" + inputContainerId + "' value='" + val + "' maxlength='4' size='4' />";
            }

            private _wrapErrorArea(renderCtx: SPClientTemplates.RenderContext_Form): string {
                var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(renderCtx);
                var errorContainerId = formCtx.fieldName + '_' + formCtx.fieldSchema.Id + '_VisaField_Error';

                this._errorContainerId = errorContainerId;

                return "<span id='" + errorContainerId + "' class='ms-formvalidation ms-csrformvalidation'></span>";
            }

            private _onGetValue(): string {

                var result = '';

                if (this._fieldIds.length == 4) {
                    for (var key in this._fieldIds) {
                        result += (<HTMLInputElement>document.getElementById(this._fieldIds[key])).value;
                    }
                }

                return result;
            }

            private _getViewStringValue(value: string): string {

                if (value && value.length == 16) {

                    var arr = [];

                    for (var i = 0; i < 4; i++)
                        arr.push(VisaFieldHelper.ParseValuePart(value, i));

                    return arr.join("-");
                }

                return ""
            }

            private viewTemplate(renderCtx, field, listItem, listSchema): string {

                var fieldValue = "";

                if (renderCtx != null && renderCtx.CurrentItem != null)
                    fieldValue = eval('renderCtx.CurrentItem.' + field.Name);

                if (fieldValue.length == 16)
                    fieldValue = this._getViewStringValue(fieldValue);

                return fieldValue;
            }

            private _initValidators(renderCtx) {

                var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(renderCtx);

                var visaFieldValidators = new SPClientForms.ClientValidation.ValidatorSet();

                if (formCtx.fieldSchema.Required) {
                    visaFieldValidators.RegisterValidator(new SPClientForms.ClientValidation.RequiredValidator());
                }

                visaFieldValidators.RegisterValidator(new spdevlab.fields.VisaFieldValidator());

                formCtx.registerValidationErrorCallback(formCtx.fieldName, (error) => { this.onError(error); });
                formCtx.registerClientValidator(formCtx.fieldName, visaFieldValidators);
            }

            private newFormTemplate(renderCtx): string {

                this._initValidators(renderCtx);

                var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(renderCtx);
                formCtx.registerGetValueCallback(formCtx.fieldName, () => { return this._onGetValue(); });

                return this._wrapIntoInput(renderCtx, "", 0) + "-" +
                    this._wrapIntoInput(renderCtx, "", 1) + "-" +
                    this._wrapIntoInput(renderCtx, "", 2) + "-" +
                    this._wrapIntoInput(renderCtx, "", 3) + this._wrapErrorArea(renderCtx);
            }

            private editFormTemplate(renderCtx): string {

                var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(renderCtx);
                var fieldValue = renderCtx.CurrentItem[renderCtx.CurrentFieldSchema.Name];

                this._initValidators(renderCtx);

                var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(renderCtx);
                formCtx.registerGetValueCallback(formCtx.fieldName, () => { return this._onGetValue(); });

                if (fieldValue.length == 16) {

                    return this._wrapIntoInput(renderCtx, VisaFieldHelper.ParseValuePart(fieldValue, 0), 0) + "-" +
                        this._wrapIntoInput(renderCtx, VisaFieldHelper.ParseValuePart(fieldValue, 1), 1) + "-" +
                        this._wrapIntoInput(renderCtx, VisaFieldHelper.ParseValuePart(fieldValue, 2), 2) + "-" +
                        this._wrapIntoInput(renderCtx, VisaFieldHelper.ParseValuePart(fieldValue, 3), 3) + this._wrapErrorArea(renderCtx);
                }

                return fieldValue;

            }

            private displayFormTemplate(renderCtx): string {

                if (renderCtx != null && renderCtx.CurrentFieldValue != null) {

                    var fieldValue = renderCtx.CurrentFieldValue.toString();

                    if (fieldValue.length == 16)
                        fieldValue = this._getViewStringValue(fieldValue);

                    return fieldValue;
                }

                return '';
            }

            private onError(error) {
                if (this._errorContainerId != null) {

                    document
                        .getElementById(this._errorContainerId)
                    .innerHTML = "<span role='alert'>" + error.errorMessage + "</span>";
                }
            }

            public Init() {

                var fieldName = this._fieldName;

                var visaFieldTemplates = {
                    Templates: {
                        Fields: {}
                    }
                };

                visaFieldTemplates.Templates.Fields[fieldName] = {};

                visaFieldTemplates.Templates.Fields[fieldName]["View"] = (renderCtx, field, listItem, listSchema) => { return this.viewTemplate(renderCtx, field, listItem, listSchema); };
                visaFieldTemplates.Templates.Fields[fieldName]["NewForm"] = (renderCtx) => { return this.newFormTemplate(renderCtx); };
                visaFieldTemplates.Templates.Fields[fieldName]["EditForm"] = (renderCtx) => { return this.editFormTemplate(renderCtx); };
                visaFieldTemplates.Templates.Fields[fieldName]["DisplayForm"] = (renderCtx) => { return this.displayFormTemplate(renderCtx); };

                SPClientTemplates.TemplateManager.RegisterTemplateOverrides(visaFieldTemplates);
            }
        }

        export class VisaFieldGridEditControl implements SP.JsGrid.EditControl {

            public Init(gridContext: any, gridTextInputElement: any) {

                var self = this;

                this._onActivateActor = () => { self._gridContext.OnActivateActor(); };
                this._onKeyDown = (e) => { self.onKeyDown(e); };
                this._onKeyUp = (e) => { self.onKeyUp(e); };
                this._onMouseDown = (e) => { self.onMouseDown(e); };

                this._gridContext = gridContext;
                this._gridTextInputElement = gridTextInputElement;

                this._cnt = document.createElement('div');
                this._cnt.style.cssText = 'visibility:hidden;position:absolute;top:0px;left:0px;background:#ffffff;border:1px #dedede solid;';

                for (var i = 0; i < 4; i++) {
                    var newTb = document.createElement('input');

                    newTb.id = "spdevlab-visafield-quickedit-" + i.toString();
                    newTb.value = i.toString();
                    newTb.style.cssText = 'position:;top:0px;left:0px;';
                    newTb.maxLength = 4;
                    newTb.size = 4;

                    this._cnt.appendChild(newTb);
                    this._tbs[i] = newTb;
                }

                this._gridContext.parentNode.appendChild(this._cnt);
            }

            private _gridContext: any = null;
            private _gridTextInputElement: any = null;

            private _cnt: any = null;
            private _cellContext: any = null;
            private _tbs: HTMLInputElement[] = [];
            private _inEdit: boolean = false;

            // to be used lated w/ $add/removeHandler
            private _onActivateActor;
            private _onKeyDown;
            private _onKeyUp;
            private _onMouseDown;

            private onKeyDown(eventInfo: any) {

                if (eventInfo.keyCode == Sys.UI.Key.tab) {
                    eventInfo.stopPropagation();
                }
                else {
                    this._gridContext.OnKeyDown(eventInfo);
                }
            }

            private onKeyUp(eventInfo: any) {

            }

            private onMouseDown(eventInfo: any) {
                this._tbs[0].focus();
                eventInfo.stopPropagation();
            }

            private _setupHandlers(attachActions: boolean) {

                var self = this;

                for (var i = 0; i < this._tbs.length; i++) {

                    var tb = this._tbs[i];

                    if (attachActions) {

                        $addHandler(tb, 'focus', self._onActivateActor);
                        $addHandler(tb, 'keydown', self._onKeyDown);
                        $addHandler(tb, 'keyup', self._onKeyUp);
                        $addHandler(tb, 'mousedown', self._onMouseDown);
                    }
                    else {
                        $removeHandler(tb, 'focus', self._onActivateActor);
                        $removeHandler(tb, 'keydown', self._onKeyDown);
                        $removeHandler(tb, 'keyup', self._onKeyUp);
                        $removeHandler(tb, 'mousedown', self._onMouseDown);
                    }
                }
            }

            public SupportedWriteMode: SP.JsGrid.EditActorWriteType = SP.JsGrid.EditActorWriteType.LocalizedOnly;
            public SupportedReadMode: SP.JsGrid.EditActorReadType = SP.JsGrid.EditActorReadType.LocalizedOnly;

            public BindToCell(cellContext: any) {
                this._cellContext = cellContext;
            }

            public OnCellMove() { }

            public Focus(eventInfo: any) {

                try {
                    this._tbs[0].focus();
                }
                catch (error) {
                    alert('Incorrectly trying to focus the EditBoxEditControl while hidden?');
                }
            }

            // TODO, make the same "parse" method for both quick edit and regular classes
            public OnBeginEdit(eventInfo: any) {

                this._inEdit = true;

                var currentValue = this._cellContext.originalValue.localized;

                if (currentValue) {
                    VisaFieldHelper.UpdateValues(this._tbs, currentValue);
                }

                this._cellContext.Show(this._cnt);

                this._setupHandlers(true);
                this.Focus(eventInfo);
            }

            public OnEndEdit(eventInfo: any) {

                this._cellContext.Hide(this._cnt);

                this._inEdit = false;
                this._setupHandlers(false);

                var value = this._tbs[0].value + "" +
                    this._tbs[1].value + "" +
                    this._tbs[2].value + "" +
                    this._tbs[3].value;

                this._cellContext
                    .SetCurrentValue({
                        localized: value
                    });
            }

            public Unbind() { }
            public Dispose() { }
        }

        export class VisaFieldValidator implements SPClientForms.ClientValidation.IValidator {

            private static _re16digit = /^\d{16}$/
            private static _re16digitErrorMessage = "Please, fill out 4 digits per every text field.";

            public Validate(value: string): SPClientForms.ClientValidation.ValidationResult {

                var value = SPClientTemplates.Utility.Trim(value);

                var hasError = !VisaFieldValidator._re16digit.test(value);
                var errorMsg = hasError ? VisaFieldValidator._re16digitErrorMessage : '';

                return new SPClientForms.ClientValidation.ValidationResult(hasError, errorMsg);
            }
        }
    }

    (function () {

        // general field support
        var field = new spdevlab.fields.VisaField("VisaField");
        field.Init();

        // quick edit support -> yeap, I did it! :)
        SP.SOD.executeOrDelayUntilScriptLoaded(function () {

            SP.GanttControl.WaitForGanttCreation(function (ganttChart) {

                var visaColumn = <SP.JsGrid.ColumnInfo>null;

                var visaFieldQuickEditId = "EDIT_SPDLAB_VISAFIELD";
                var columns = ganttChart.get_Columns();

                for (var i = 0; i < columns.length; i++) {
                    if (columns[i].columnKey == "VisaField") {
                        visaColumn = columns[i];
                        break;
                    }
                }

                visaColumn.fnGetEditControlName = (record, fieldKey) => {
                    return visaFieldQuickEditId;
                };

                SP.JsGrid.PropertyType.Utils.RegisterEditControl(visaFieldQuickEditId, function (gridContext, cellControl) {
                    var editorInstance = new spdevlab.fields.VisaFieldGridEditControl();
                    editorInstance.Init(gridContext, cellControl);

                    return editorInstance;
                }, []);
            });

        }, "spgantt.js");
    })();
}